package fun.stgoder.easydarwin.jobs.comm.util;

import fun.stgoder.easydarwin.jobs.comm.model.Cmd;
import fun.stgoder.easydarwin.jobs.comm.model.Out;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

public class ProcessUtil {

    private static Logger logger = LoggerFactory.getLogger(ProcessUtil.class);

    public static Out exec(String cmd) throws Exception {
        try {
            final Process p0 = Runtime.getRuntime().exec(cmd);
            if (p0 == null)
                return null;

            StringBuilder output = new StringBuilder();
            try (BufferedReader outputReader = new BufferedReader(new InputStreamReader(p0.getInputStream()))) {
                String line = null;
                while ((line = outputReader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            StringBuilder errs = new StringBuilder();
            try (BufferedReader errReader = new BufferedReader(new InputStreamReader(p0.getErrorStream()))) {
                String line = null;
                while ((line = errReader.readLine()) != null) {
                    errs.append(line).append("\n");
                }
            }

            p0.waitFor(10, TimeUnit.SECONDS);
            int exitValue = p0.exitValue();

            logger.info("exitValue: " + exitValue);
            logger.info("out: " + output.toString());
            logger.info("errs: " + errs.toString());
            return new Out(exitValue, output.toString(), errs.toString());
        } catch (IOException | InterruptedException e) {
            logger.error("process exec", e);
            throw new Exception("process exec err: " + e.getMessage());
        }
    }

    public static Out exec(Cmd cmd) throws Exception {

        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(cmd.cmds());
            final Process p0 = builder.start();

            StringBuilder output = new StringBuilder();
            try (BufferedReader outputReader = new BufferedReader(new InputStreamReader(p0.getInputStream()))) {
                String line = null;
                while ((line = outputReader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            StringBuilder errs = new StringBuilder();
            try (BufferedReader errReader = new BufferedReader(new InputStreamReader(p0.getErrorStream()))) {
                String line = null;
                while ((line = errReader.readLine()) != null) {
                    errs.append(line).append("\n");
                }
            }

            p0.waitFor(10, TimeUnit.SECONDS);
            int exitValue = p0.exitValue();

            logger.info("exitValue: " + exitValue);
            logger.info("out: " + output.toString());
            logger.info("errs: " + errs.toString());
            return new Out(exitValue, output.toString(), errs.toString());
        } catch (Exception e) {
            logger.error("process exec", e);
            throw new Exception("process exec err: " + e.getMessage());
        }
    }

    public static Process execSilent(Cmd cmd) throws Exception {
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(cmd.cmds());
            Process process = builder.start();
            return process;
        } catch (Exception e) {
            logger.error("process exec", e);
            throw new Exception("process exec err: " + e.getMessage());
        }
    }

    public static int execRedirect(Cmd cmd, String outputDirPath) throws Exception {
        try {
            ProcessBuilder builder = new ProcessBuilder();
            Process p0 = builder.command(cmd.cmds())
                    .redirectError(new File(outputDirPath + File.separator + "errs"))
                    .redirectOutput(new File(outputDirPath + File.separator + "output"))
                    .start();
            boolean b = p0.waitFor(30, TimeUnit.SECONDS);
            if (!b) {
                System.out.println("execRedirect timeout");
            }
            return p0.exitValue();
        } catch (Exception e) {
            logger.error("process exec", e);
            throw new Exception("process exec err: " + e.getMessage());
        }
    }

    private ProcessUtil() {

    }
}
